import java.io.IOException;
import java.net.UnknownHostException;


/**
 * The Model part of the application. Does all the work behind the {@link View}.<p>
 * Contains the main driver method.
 * 
 * @author Alex Mackay
 */
public class Model {
	
	public static final int DEFAULT_PORT = 1337;
	
	public static void main(String[] args) throws java.rmi.RemoteException{
		
		int port = DEFAULT_PORT;
		Model model;
		
		if(args.length == 0) {
			model = new Model(true);
			model.startServer(DEFAULT_PORT);
			
		} else if(args.length == 1) {
			try {
				port = Integer.valueOf(args[0]);
				
			} catch(NumberFormatException nfe){
				System.err.println("Port must be numeric");
				System.exit(0);
			}
			model = new Model(true);
			model.startServer(port);
			
		} else if(args.length == 2){
			
			String host = args[0];
			
			try {
				model = new Model(false);
				port = Integer.valueOf(args[1]);
				model.connectToRemoteServer(host, port);
				
			} catch (UnknownHostException e) {
				System.err.println("Unable to connect to host: " + host + " on port " + port);
				System.exit(0);
			} catch (IOException e) {
				System.err.println("Unable to connect to host: " + host + " on port " + port);
				System.exit(0);
			} catch(NumberFormatException nfe){
				System.err.println("Port must be numeric");
				System.exit(0);
			}
			
		} else {
			System.out.println("usage:");
			System.out.println("java Model <> - creates a master on port 1337");
			System.out.println("java Model <port> - creates a master on specified port");
			System.out.println("java Model <masterServer Name><port> - creates a slave connecting to master on port");
		}
	}
	
	
	private View view;
	private CardsServer server;
	private PlayerModel localplayer;
	private Room room;
	
	private Thread serverThread;
	private Thread clientThread;
	private Connection connection;
	
	
	/**
	 * Constructs a <code>Model</code> object and sets a new {@link View}
	 */
	public Model(boolean isServer) {
		if (!isServer) 
			this.setView(new View(this));
		
		Table t = new Table();
		t.addDeck(new Deck("PlayingCards"));
		room = new Room(t);
	}
	
	
	/**
	* Starts a local server. Creates a local client
	*/
	public void startServer(int port) {

		try {
			server = new CardsServer(port, this);
			serverThread = new Thread(server);
			serverThread.start();
			
			//create local client
			Model client = new Model(false);
			client.connectToRemoteServer("localhost", port);
			
		} catch (IOException e) {
			System.err.println("Could not bind server to port " + port);
			e.printStackTrace();
		}
	}
	
	
	/**
	 * Sets the {@link PlayerModel} for this <code>Model</code>
	 * 
	 * @param pm The model to set.
	 */
	public void setPlayer(PlayerModel model) {
		this.localplayer = model;
		view.setPlayer(localplayer);
	}
	
		
	/**
	* Connects the local program to a remote server. Creates the {@link Connection} object to handle the connection.
	* 
	* @param host The hostname of the server to connect to.
	* @param The port of the server to connect to.
	* @throws IOException 
	*/
	public void connectToRemoteServer(String host, int port) throws UnknownHostException, IOException {
		connection = new Connection(host, port);
		setPlayer(new PlayerModel(new PlayerData(),connection, this));
		connection.setPlayer(localplayer);
		clientThread = new Thread(connection);
		clientThread.start();
	}
	
	
	/**
	 * Sets the {@link View} object for this <code>Model</code>.
	 * 
	 * @param view The <code>View</view> object to set.
	 */
	public void setView(View view) {
		this.view = view;
	}	
	
	
	/**
	 * Updates the {@link View} to reflect changes in the <code>Model</code>.
	 */
	public void updateView() {
		view.repaint();
		localplayer.alert();
	}
	
	/**
	 * Stops the locally running server.
	 */
	public void stopServer() {
		server.stopServer();
	}
	
	/**
	 * @return The {@link Room} object.
	 */
	public Room getRoom() {
		return room;
	}
}
